# -*- coding: utf-8 -*-
"""
Created on Fri Mar 15 22:56:01 2024

@author: Lenovo
"""

import torch
from torch.autograd import Variable
import os
import random
import linecache
import numpy as np
import torchvision
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from train import SiameseNetwork
from PIL import Image
import PIL.ImageOps
import matplotlib.pyplot as plt
import torch.nn.functional as F
import cv2


transform=transforms.Compose(
        [transforms.Resize((100, 100)), transforms.ToTensor()])
'''
model = torch.load('model.pth2').cuda()
model.eval()
'''
model = torch.load('model.pth', map_location=torch.device('cpu'))
model.eval()

'''  实际图片测试  01
img1 = PIL.Image.open(r'D:\luanshengNT\att_faces\s55\1.jpg')
img2 = PIL.Image.open(r'D:\luanshengNT\att_faces\s55\2.jpg')


02
img1 = PIL.Image.open(r'D:\luanshengNT\att_faces\s55\3.jpg')
img2 = PIL.Image.open(r'D:\luanshengNT\att_faces\s55\4.jpg')


正反例测试
'''
'''  测试组1
img1 = PIL.Image.open(r'D:\luanshengNT\att_faces\s22\1.pgm')
img2 = PIL.Image.open(r'D:\luanshengNT\att_faces\s7\9.pgm') 
'''
 
img1 = PIL.Image.open(r'D:\luanshengNT\KinFaceW-I\images\father-dau\fd_039_1.jpg')
img2 = PIL.Image.open(r'D:\luanshengNT\KinFaceW-I\images\father-dau\fd_040_2.jpg')


img1 = img1.convert("L")
img2 = img2.convert("L")
 
img11 = transform(img1)
img22 = transform(img2)
 
imgs1 = np.array(img11)
imgs1 = imgs1[0,...]
imgs2 = np.array(img22)
imgs2 = imgs2[0,...]
print(imgs1.shape)
 
input1 = img11.unsqueeze(0)
input2 = img22.unsqueeze(0)
''' 
output1, output2 = model(Variable(input1).cuda(), Variable(input2).cuda())


euclidean_distance = F.pairwise_distance(output1, output2)
#plt.imshow
diff = euclidean_distance.cpu().detach().numpy()[0]
print(euclidean_distance.cpu().detach().numpy()[0])
'''


output1, output2 = model(Variable(input1), Variable(input2))
# 计算欧氏距离
euclidean_distance = F.pairwise_distance(output1, output2)

# 可视化
diff = euclidean_distance.detach().numpy()[0]
print(euclidean_distance.detach().numpy()[0])
 
plt.subplot(1, 2, 1)
plt.title('diff='+str(diff))
plt.imshow(imgs1)
plt.subplot(1, 2, 2)
plt.imshow(imgs2)
 
plt.show()
#%%

# 定义钩子函数来获取卷积层的输出
features = []

def hook_fn(module, input, output):
    features.append(output)

# 注册钩子函数到每个卷积层
model.cnn1[0].register_forward_hook(hook_fn)
model.cnn1[4].register_forward_hook(hook_fn)
model.cnn1[8].register_forward_hook(hook_fn)

# 加载并预处理测试图片
transform = transforms.Compose([
    transforms.Resize((100, 100)),  # 调整大小
    transforms.ToTensor(),  # 转为张量

])

#image = Image.open(r'D:\luanshengNT\att_faces\s22\1.pgm')  # 加载图片


#image = Image.open(r'D:\luanshengNT\KinFaceW-I\images\test\02.jpg') 
#image = image.convert("L")


image=Image.open(r'D:\luanshengNT\KinFaceW-I\images\father-dau\fd_052_2.jpg')
image = image.convert("L")
image = transform(image).unsqueeze(0)  # 添加 batch 维度

# 前向传播
with torch.no_grad():
    output = model.forward_once(image)

# 获取卷积层的输出
conv1_output = features[0]
conv2_output = features[1]
conv3_output = features[2]

# 可视化卷积层的输出
def visualize_feature_map(feature_map):
    num_features = feature_map.shape[1]  # 获取特征图的通道数
    fig, axes = plt.subplots(1, num_features, figsize=(20, 5))  # 创建子图

    for i in range(num_features):
        feature = feature_map[0, i, :, :]  # 获取单个特征图
        axes[i].imshow(feature, cmap='viridis')  # 使用热图显示特征图
        axes[i].axis('off')
        axes[i].set_title('Feature Map {}'.format(i+1))

    plt.show()

# 可视化卷积层的输出特征图
visualize_feature_map(conv1_output)
visualize_feature_map(conv2_output)
visualize_feature_map(conv3_output)

#%%后20%数据测试
model = torch.load('model.pth', map_location=torch.device('cpu'))
model.eval()
# 图像预处理
transform = transforms.Compose([
    transforms.Resize((100, 100)),  # 调整图像大小
    transforms.ToTensor(),           # 转换为Tensor
])
loss_contrastive01=0.80
# 读取TXT文件
with open('D:\luanshengNT\KinFaceW-I\\train20%.txt', 'r') as f:  # TXT文件路径
    lines = f.readlines()

# 初始化变量
total = 0
correct = 0
true_positive = 0
false_positive = 0
false_negative = 0
true_negative = 0

# 测试模型
for i in range(0, len(lines), 2):  # 以步长为2进行迭代
    img_path1, label1 = lines[i].strip().split()  # 读取第一个图片路径和标签
    img_path2, label2 = lines[i + 1].strip().split()  # 读取第二个图片路径和标签
    img1 = Image.open(img_path1).convert('RGB')  # 打开第一个图像并转换为RGB
    img2 = Image.open(img_path2).convert('RGB')  # 打开第二个图像并转换为RGB
    img1 = img1.convert("L")
    img2 = img2.convert("L")
    img1 = transform(img1)  # 对第一个图像应用预处理
    img2 = transform(img2)  # 对第二个图像应用预处理
    img1 = img1.unsqueeze(0)  # 增加batch维度
    img2 = img2.unsqueeze(0)  # 增加batch维度

    with torch.no_grad():
            output1, output2 = model(img1, img2)  # 输入相同的图像进行测试
            euclidean_distance = F.pairwise_distance(output1, output2)  # 计算欧氏距离

    # 根据欧氏距离判断是否匹配
    if euclidean_distance.item() < loss_contrastive01:  # 损失函数阈值
            prediction = 1  # 匹配
            print('匹配')
    else:
            prediction = 0  # 不匹配
            print('不匹配')

    total += 1
    if prediction == 1:
            correct += 1
    print(euclidean_distance)
    if int(label1) == int(label2) and prediction == 1:
        true_positive += 1
    elif int(label1) != int(label2) and prediction == 1:
        false_positive += 1
    elif int(label1) == int(label2) and prediction == 0:
        false_negative += 1
    else:
        true_negative += 1

# 计算准确率
accuracy = (true_positive + true_negative) / total * 100

# 计算精确率、召回率、错误率
precision = true_positive / (true_positive + false_positive)*100
recall = true_positive / (true_positive + false_negative)*100
error_rate = (false_positive + false_negative) / total * 100
# 计算准确率
#accuracy = correct / total * 100
#print(f'Accuracy: {accuracy:.2f}%')


print(f'Accuracy准确率: {accuracy:.2f}%')
print(f'Precision精确率: {precision:.2f}%')
print(f'Recall召回率: {recall:.2f}%')
print(f'error_rate错误率：{error_rate:.2f}%')
#%%
data = [accuracy, precision, recall, error_rate]

# 定义标签
labels = ['accuracy', 'precision', 'recall', 'error_rate']

# 创建柱状图
plt.bar(labels, data, color=['blue', 'green', 'orange', 'red'])

# 添加标签和标题
plt.xlabel('Metrics')
plt.ylabel('Value')
plt.title('Visualization of Metrics')

# 显示图形
plt.show()